diff options
Diffstat (limited to 'src/pages/blog/[...date].astro')
-rw-r--r-- | src/pages/blog/[...date].astro | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/pages/blog/[...date].astro b/src/pages/blog/[...date].astro new file mode 100644 index 0000000..1742baa --- /dev/null +++ b/src/pages/blog/[...date].astro @@ -0,0 +1,161 @@ +--- +import type { + GetStaticPaths, + InferGetStaticParamsType, + InferGetStaticPropsType, +} from "astro"; +import { getCollection } from "astro:content"; +import Base from "@layouts/Base.astro"; +import DateSelector from "@components/DateSelector.astro"; +import BlogCard from "@components/BlogCard.astro"; +import { sortLastCreated } from "@lib/collection/helpers"; + +export const getStaticPaths = (async () => { + const posts = await getCollection("blog"); + + const archive = { + years: new Set<number>(), + monthsByYear: new Map<string, Set<number>>(), + daysByMonth: new Map<string, Set<number>>(), + postsByDate: new Map<string, typeof posts>(), + sortedDates: [] as string[], + }; + + const getYMD = (date: Date) => { + const y = date.getFullYear(); + const m = date.getMonth() + 1; + const d = date.getDate(); + return { y, m, d }; + }; + + for (const post of posts) { + const { y, m, d } = getYMD(post.data.dateCreated); + + archive.years.add(y); + + if (!archive.monthsByYear.has(y.toString())) { + archive.monthsByYear.set(y.toString(), new Set()); + } + archive.monthsByYear.get(y.toString())!.add(m); + + const ym = `${y}/${String(m).padStart(2, "0")}`; + if (!archive.daysByMonth.has(ym)) archive.daysByMonth.set(ym, new Set()); + archive.daysByMonth.get(ym)!.add(d); + + const ymd = `${ym}/${String(d).padStart(2, "0")}`; + if (!archive.postsByDate.has(ymd)) archive.postsByDate.set(ymd, []); + archive.postsByDate.get(ymd)!.push(post); + } + + archive.sortedDates = Array.from(archive.postsByDate.keys()).sort(); + + const paths = []; + + const sortedYears = Array.from(archive.years).sort(); + + const lastYear = Math.max(...sortedYears.map(Number)); + paths.push({ + params: { year: undefined }, + props: { + posts: posts.filter((p) => + p.data.dateCreated.getFullYear() === lastYear + ), + next: undefined, + previous: sortedYears?.[sortedYears.length - 2], + years: sortedYears, + months: Array.from(archive.monthsByYear.get(lastYear.toString()) ?? []), + }, + }); + + for (const y of sortedYears) { + const yearPosts = posts.filter((p) => + p.data.dateCreated.getFullYear() === Number(y) + ); + const idx = sortedYears.indexOf(y); + paths.push({ + params: { year: y }, + props: { + posts: yearPosts, + next: sortedYears?.[idx + 1], + previous: sortedYears?.[idx - 1], + years: sortedYears, + months: Array.from(archive.monthsByYear.get(y.toString()) ?? []), + }, + }); + } + + const allMonths = Array.from(archive.monthsByYear.entries()) + .flatMap(([year, mset]) => + Array.from(mset).map((m) => `${year}/${String(m).padStart(2, "0")}`) + ) + .sort(); + + for (const [y, months] of archive.monthsByYear) { + const sortedMonths = Array.from(months).sort(); + for (const m of sortedMonths) { + const monthPosts = posts.filter((p) => { + const d = p.data.dateCreated; + return ( + d.getFullYear() === Number(y) && + d.getMonth() + 1 === m + ); + }); + + const ym = `${y}/${String(m).padStart(2, "0")}`; + const idx = allMonths.indexOf(ym); + + paths.push({ + params: { year: ym }, + props: { + posts: monthPosts, + next: allMonths?.[idx + 1], + previous: allMonths?.[idx - 1], + years: sortedYears, + months: Array.from(months).sort(), + days: Array.from(archive.daysByMonth.get(ym) ?? []).sort(), + }, + }); + } + } + + for (let i = 0; i < archive.sortedDates.length; i++) { + const ymd = archive.sortedDates[i]; + const [y, m] = ymd.split("/"); + paths.push({ + params: { year: ymd }, + props: { + posts: archive.postsByDate.get(ymd) ?? [], + next: archive.sortedDates?.[i + 1], + previous: archive.sortedDates?.[i - 1], + years: sortedYears, + months: Array.from(archive.monthsByYear.get(y) ?? []).sort(), + days: Array.from(archive.daysByMonth.get(`${y}/${m}`) ?? []).sort(), + }, + }); + } + + return paths; +}) satisfies GetStaticPaths; + +export type Params = InferGetStaticParamsType<typeof getStaticPaths>; +export type Props = InferGetStaticPropsType<typeof getStaticPaths>; + +const title = "Blog"; +const description = "Latest articles."; + +let { posts, previous, next, years, months, days } = Astro.props; +posts = posts.sort(sortLastCreated); +const date = posts[0].data.dateCreated as Date; +--- + +<Base {title} {description}> + <main> + <h2>Blogue</h2> + {date && <DateSelector {date} {years} {months} {days} />} + {posts.map((post) => <BlogCard {...post} />)} + <div> + {previous && <a href={`/blog/${Astro.props.previous}`}>Previous</a>} + {next && <a href={`/blog/${Astro.props.next}`}>Next</a>} + </div> + </main> +</Base> |